// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraSettingKeyboardInput.h"

#include "EnhancedInputSubsystems.h"
#include "../LyraSettingsLocal.h"
#include "Player/LyraLocalPlayer.h"
#include "PlayerMappableInputConfig.h"
#include "EnhancedInputSubsystems.h"
#include "UserSettings/EnhancedInputUserSettings.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraSettingKeyboardInput)

class ULocalPlayer;

#define LOCTEXT_NAMESPACE "LyraSettings"

namespace Lyra::ErrorMessages
{
	static const FText UnknownMappingName = LOCTEXT("LyraErrors_UnknownMappingName", "未知映射"); // 未知映射错误文本
}

/**
 * 构造函数
 */
ULyraSettingKeyboardInput::ULyraSettingKeyboardInput()
{
	bReportAnalytics = false; // 不报告分析数据
}

/**
 * 获取设置显示名称
 */
FText ULyraSettingKeyboardInput::GetSettingDisplayName() const
{
	if (const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
	{
		if (Row->HasAnyMappings()) // 如果有任何映射
		{
			return Row->Mappings.begin()->GetDisplayName(); // 返回第一个映射的显示名称
		}
	}
	
	return Lyra::ErrorMessages::UnknownMappingName; // 返回未知映射错误文本
}

/**
 * 获取设置显示分类
 */
FText ULyraSettingKeyboardInput::GetSettingDisplayCategory() const
{
	if (const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
	{
		if (Row->HasAnyMappings()) // 如果有任何映射
		{
			return Row->Mappings.begin()->GetDisplayCategory(); // 返回第一个映射的显示分类
		}
	}

	return Lyra::ErrorMessages::UnknownMappingName; // 返回未知映射错误文本
}

/**
 * 查找键位映射行
 */
const FKeyMappingRow* ULyraSettingKeyboardInput::FindKeyMappingRow() const
{
	if (const UEnhancedPlayerMappableKeyProfile* Profile = FindMappableKeyProfile()) // 查找可映射键位配置文件
	{
		return Profile->FindKeyMappingRow(ActionMappingName); // 返回动作映射名称对应的键位映射行
	}

	ensure(false); // 确保不会执行到这里
	return nullptr; // 返回空指针
}

/**
 * 查找可映射键位配置文件
 */
UEnhancedPlayerMappableKeyProfile* ULyraSettingKeyboardInput::FindMappableKeyProfile() const
{
	if (UEnhancedInputUserSettings* Settings = GetUserSettings()) // 获取用户设置
	{
		return Settings->GetKeyProfileWithId(ProfileIdentifier); // 返回配置文件标识符对应的键位配置文件
	}
	
	ensure(false); // 确保不会执行到这里
	return nullptr; // 返回空指针
}

/**
 * 获取用户设置
 */
UEnhancedInputUserSettings* ULyraSettingKeyboardInput::GetUserSettings() const
{
	if(ULyraLocalPlayer* LyraLocalPlayer = Cast<ULyraLocalPlayer>(LocalPlayer)) // 转换为Lyra本地玩家
	{
		// 将键位映射到玩家键位配置文件
		if (UEnhancedInputLocalPlayerSubsystem* System = LyraLocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) // 获取增强输入本地玩家子系统
		{
			return System->GetUserSettings(); // 返回用户设置
		}
	}
	
	return nullptr; // 返回空指针
}

/**
 * 初始化时调用
 */
void ULyraSettingKeyboardInput::OnInitialized()
{
	DynamicDetails = FGetGameSettingsDetails::CreateLambda([this](ULocalPlayer&) // 创建动态详情Lambda
	{
		if (const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
		{
			if (Row->HasAnyMappings()) // 如果有任何映射
			{
				return FText::Format(LOCTEXT("DynamicDetails_KeyboardInputAction", "{0}的绑定"), Row->Mappings.begin()->GetDisplayName()); // 返回格式化文本
			}
		}
		return FText::GetEmpty(); // 返回空文本
	});

	Super::OnInitialized(); // 调用父类初始化方法
}

/**
 * 初始化输入数据
 */
void ULyraSettingKeyboardInput::InitializeInputData(const UEnhancedPlayerMappableKeyProfile* KeyProfile, const FKeyMappingRow& MappingData, const FPlayerMappableKeyQueryOptions& InQueryOptions)
{
	check(KeyProfile); // 检查键位配置文件有效性

	ProfileIdentifier = KeyProfile->GetProfileIdString(); // 设置配置文件标识符
	QueryOptions = InQueryOptions; // 设置查询选项
	
	for (const FPlayerKeyMapping& Mapping : MappingData.Mappings) // 遍历映射数据
	{
		// 仅添加通过查询过滤器提供的映射
		if (!KeyProfile->DoesMappingPassQueryOptions(Mapping, QueryOptions)) // 检查映射是否通过查询选项
		{
			continue; // 跳过不满足条件的映射
		}
		
		ActionMappingName = Mapping.GetMappingName(); // 设置动作映射名称
		InitialKeyMappings.Add(Mapping.GetSlot(), Mapping.GetCurrentKey()); // 添加初始键位映射
		const FText& MappingDisplayName =Mapping.GetDisplayName(); // 获取映射显示名称
		
		if (!MappingDisplayName.IsEmpty()) // 如果显示名称不为空
		{
			SetDisplayName(MappingDisplayName);	// 设置显示名称
		}
	}
	
	const FString NameString = TEXT("KBM_Input_") + ActionMappingName.ToString(); // 构建名称字符串
	SetDevName(*NameString); // 设置开发名称
}

/**
 * 根据插槽获取键位文本
 */
FText ULyraSettingKeyboardInput::GetKeyTextFromSlot(const EPlayerMappableKeySlot InSlot) const
{
	if (const UEnhancedPlayerMappableKeyProfile* Profile = FindMappableKeyProfile()) // 查找可映射键位配置文件
	{
		FPlayerMappableKeyQueryOptions QueryOptionsForSlot = QueryOptions; // 复制查询选项
		QueryOptionsForSlot.SlotToMatch = InSlot; // 设置要匹配的插槽
		
		if (const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
		{
			for (const FPlayerKeyMapping& Mapping : Row->Mappings) // 遍历映射
			{
				if (Profile->DoesMappingPassQueryOptions(Mapping, QueryOptionsForSlot)) // 检查映射是否通过查询选项
				{
					return Mapping.GetCurrentKey().GetDisplayName(); // 返回当前键位的显示名称
				}
			}
		}
	}
	
	return EKeys::Invalid.GetDisplayName(); // 返回无效键位的显示名称
}

/**
 * 重置为默认值
 */
void ULyraSettingKeyboardInput::ResetToDefault()
{	
	if (UEnhancedInputUserSettings* Settings = GetUserSettings()) // 获取用户设置
	{
		FMapPlayerKeyArgs Args = {}; // 初始化映射玩家键位参数
		Args.MappingName = ActionMappingName; // 设置映射名称

		FGameplayTagContainer FailureReason; // 失败原因容器
		Settings->ResetAllPlayerKeysInRow(Args, FailureReason); // 重置行中所有玩家键位

		NotifySettingChanged(EGameSettingChangeReason::Change); // 通知设置已更改
	}
}

/**
 * 存储初始设置
 */
void ULyraSettingKeyboardInput::StoreInitial()
{
	if (const UEnhancedPlayerMappableKeyProfile* Profile = FindMappableKeyProfile()) // 查找可映射键位配置文件
	{
		if(const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
		{
			for (const FPlayerKeyMapping& Mapping : Row->Mappings) // 遍历映射
			{
				if (Profile->DoesMappingPassQueryOptions(Mapping, QueryOptions)) // 检查映射是否通过查询选项
				{
					ActionMappingName = Mapping.GetMappingName(); // 设置动作映射名称
					InitialKeyMappings.Add(Mapping.GetSlot(), Mapping.GetCurrentKey());	// 添加初始键位映射
				}
			}
		}
	}
}

/**
 * 恢复到初始值
 */
void ULyraSettingKeyboardInput::RestoreToInitial()
{
	for (TPair<EPlayerMappableKeySlot, FKey> Pair : InitialKeyMappings) // 遍历初始键位映射
	{
		ChangeBinding((int32)Pair.Key, Pair.Value);	// 更改绑定
	}
}

/**
 * 更改绑定
 */
bool ULyraSettingKeyboardInput::ChangeBinding(int32 InKeyBindSlot, FKey NewKey)
{
	if (!NewKey.IsGamepadKey()) // 如果不是游戏手柄键位
	{
		FMapPlayerKeyArgs Args = {}; // 初始化映射玩家键位参数
		Args.MappingName = ActionMappingName; // 设置映射名称
		Args.Slot = (EPlayerMappableKeySlot) (static_cast<uint8>(InKeyBindSlot)); // 设置插槽
		Args.NewKey = NewKey; // 设置新键位
		// 如果需要，可以额外指定此映射仅应用于特定硬件设备或键位配置文件
		//Args.ProfileId =
		//Args.HardwareDeviceId =
		
		if (UEnhancedInputUserSettings* Settings = GetUserSettings()) // 获取用户设置
		{
			FGameplayTagContainer FailureReason; // 失败原因容器
			Settings->MapPlayerKey(Args, FailureReason); // 映射玩家键位
			NotifySettingChanged(EGameSettingChangeReason::Change); // 通知设置已更改
		}

		return true; // 返回成功
	}

	return false; // 返回失败
}

/**
 * 获取键位映射的所有动作
 */
void ULyraSettingKeyboardInput::GetAllMappedActionsFromKey(int32 InKeyBindSlot, FKey Key, TArray<FName>& OutActionNames) const
{	
	if (const UEnhancedPlayerMappableKeyProfile* Profile = FindMappableKeyProfile()) // 查找可映射键位配置文件
	{		
		Profile->GetMappingNamesForKey(Key, OutActionNames); // 获取键位对应的映射名称
	}
}

/**
 * 检查映射是否已自定义
 */
bool ULyraSettingKeyboardInput::IsMappingCustomized() const
{
	bool bResult = false; // 初始化结果为false

	if (const UEnhancedPlayerMappableKeyProfile* Profile = FindMappableKeyProfile()) // 查找可映射键位配置文件
	{
		FPlayerMappableKeyQueryOptions QueryOptionsForSlot = QueryOptions; // 复制查询选项

		if (const FKeyMappingRow* Row = FindKeyMappingRow()) // 查找键位映射行
		{
			for (const FPlayerKeyMapping& Mapping : Row->Mappings) // 遍历映射
			{
				if (Profile->DoesMappingPassQueryOptions(Mapping, QueryOptionsForSlot)) // 检查映射是否通过查询选项
				{
					bResult |= Mapping.IsCustomized(); // 更新自定义状态
				}
			}
		}
	}

	return bResult; // 返回结果
}

#undef LOCTEXT_NAMESPACE